
// 打补丁 (把比较出来的补丁 重新渲染到真实dom上)

import {
  ATTR,
  TEXT,
  REPLACE,
  REMOVE
} from './patchesTypes';
import Element from './Element';
import { setAttrs, render } from './virtual';

let finalPatches = {}, // 保存最终的这个补丁包
    rnIndex = 0; // 保存真实节点的节点下标(编号)

function doPatch(rDom, patches) {
  finalPatches = patches;
  rNodeWalk(rDom);
}

function rNodeWalk(rNode) { // 遍历真实节点，打上补丁
  // console.log(rnIndex, finalPatches[rnIndex]);
  const rnPatch = finalPatches[rnIndex ++], // 每取一次++, 一个节点一个节点的把对应的节点的补丁取出
        childNodes = rNode.childNodes; // 获取子节点(类数组)
  // console.log(childNodes);
  [...childNodes].map((c) => { // 递归调用
    rNodeWalk(c);
  });

  if (rnPatch) { // 如果当前这个节点存在补丁就打补丁
    // console.log('111', rNode, rnPatch)
    patchAction(rNode, rnPatch);
  }
}

function patchAction(node, patch) { // 给节点打上补丁
  patch.map(p => { 
    switch (p.type) {
      case ATTR: // 如果是属性补丁就遍历根据对应的属性进行修改
        for (let key in p.attrs) {
          const value = p.attrs[key];

          if (value) // 如果存在就添加，不存在就删除
            setAttrs(node, key, value);
          else
            node.removeAttribute(key);
        }
        break;
      case TEXT:
        node.textContent = p.text
        break;
      case REPLACE:
        const newNode = (p.newNode instanceof Element) // 替换类型操作时，判断是虚拟节点还是文本节点
                        ? render(p.newNode)
                        : document.createTextNode(p.newNode);
        // console.log('替换', node, patch, newNode)
        // console.log(node.parentNode);
        node.parentNode.replaceChild(newNode, node);
        break;
      case REMOVE:
        // console.log('删除', node, patch)
        node.parentNode.removeChild(node);
        break;
      default:
        break;
    }
  });
}

export default doPatch;

// const patches = { // 补丁包结构
//   0: [
//     {
//       type: 'ATTR',
//       attrs: {
//         class: '属性'
//       }
//     }
//   ],
//   1: [
//     {
//       type: 'TEXT',
//       text: 'xxxxxx'
//     }
//   ],
//   3: [
//     {
//       type: 'REMOVE',
//       index: 3
//     }
//   ],
//   6: [
//     {
//       type: 'REPLACE',
//       newNode: newNode
//     }
//   ]
// }